iT邦幫忙

2023 iThome 鐵人賽

DAY 23
1
SideProject30

一起成為新世紀文字藝術師:深入玩轉 Unicode 和 OpenType系列 第 23

DAY 23|Color Picker:使用者自定義

  • 分享至 

  • xImage
  •  

在昨天的文章裡,我們透過 FontKit 拆解 Noto Color Emoji,從 CPAL table 得知,小海豚 🐬 由四個顏色所組成的。而在今天,我們將好好的利用這些色彩資訊。

建立色彩資訊的 Array

font.CPAL.colorRecords 裡,可以印出相關的色彩:

~ console.log(font.CPAL.colorRecords)
> (4) 0: {blue: 166, green: 109, red: 0, alpha: 255, parent: {…}, …}
      1: {blue: 48, green: 43, red: 45, alpha: 255, parent: {…}, …}
      2: {blue: 225, green: 180, red: 54, alpha: 255, parent: {…}, …}
      3: {blue: 245, green: 236, red: 221, alpha: 255, parent: {…}, …}

以及藉由 font.CPAL.numPaletteEntries,知道該色彩的總數目:

~ console.log(font.CPAL.numPaletteEntries)
> 4

但光只有印出來而已是沒用的,我們需要建立一個空的 Array 來儲存這些顏色,方便更進一步的調用:

~ const originalPaletteObjects = font.CPAL.colorRecords.slice(
        font.CPAL.colorRecordIndices[0],
        font.CPAL.colorRecordIndices[0] + font.CPAL.numPaletteEntries
    )
~ console.log(originalPaletteObjects)        
> (4) [{…}, {…}, {…}, {…}]
    0: {blue: 166, green: 109, red: 0, alpha: 255, parent: {…}, …}
    1: {blue: 48, green: 43, red: 45, alpha: 255, parent: {…}, …}
    2: {blue: 225, green: 180, red: 54, alpha: 255, parent: {…}, …}
    3: {blue: 245, green: 236, red: 221, alpha: 255, parent: {…}, …}

接著,再把 Objects 按照 RGBA 的順序分割出來,成為一個一個 sub array:

~ const originalPalette = originalPaletteObjects.map(
        ele => [ele.red, ele.green, ele.blue, ele.alpha]
     );
~ console.log(originalPalette)      
> (4) [Array(4), Array(4), Array(4), Array(4)]
    0: (4) [0, 109, 166, 255]
    1: (4) [45, 43, 48, 255]
    2: (4) [54, 180, 225, 255]
    3: (4) [221, 236, 245, 255]

建立 Color Picker 們

有了色彩資訊之後,我們可以做多個 color picker,讓使用者可以自由地選擇想要的顏色。我們先在 html 裡面加一個 tag,用來放 color picker 們:

<style id="palette-overrides"></style>
<div id="color-pickers"></div>

而在 js 檔案裡面:

const colorPickers = document.getElementById("color-pickers");

originalPalette.forEach((rgbaColorArray, idx) => {
    // 為每一個顏色建立獨立的選色盤 
    const picker = document.createElement("input");
    picker.type = "color";

    // 轉換顏色
    picker.value = "#" + rgbaColorArray
        .slice(0, 3) // 不需要 alpha 值
        .map(ele => ele.toString(16)) // 轉成 16 進位
        .map(ele => ele.length == 1 ? "0" + ele : ele) // 補零
        .join("");


    // 把一個一個的選色盤加到 color-pickers 的 tag 底下
    colorPickers.appendChild(picker);

    // 監聽選色盤,在使用者操作時觸發 updateColors() function
    // 將新選到的顏色加到 override-color 屬性裡
    picker.addEventListener("input", (event) => {
        updateColorsPalette(idx, event.target.value)
    });
});

這裡面的 <input type="color"> 要特別注意,其 value 的設定只能是十六進位的值。在我們之前儲存的 originalPalette 裡面,都是 RGBA 格式,所以像是第 0 個顏色 [0, 109, 166, 255] 代表的 rgba(0, 109, 166, 255),必須要轉成十六進位的 #006da6If you have colors that are in any other format (such as CSS color names or CSS color functions such as rgb() or rgba()), you'll have to convert them to hexadecimal before setting the value.),所以需要進行以下的操作:

  • .slice(0, 3):首先先省略代表透明度的 alpha 值,反正我們也用不到
  • .map(ele => ele.toString(16)):接著將 RGB 的數值轉成 16 進位(大小寫都可以)
  • .map(ele => ele.length == 1 ? "0" + ele : ele):如果轉出來的 16 進位值只有一位的話,就在前面補 0 直到兩位
  • .join(""):把 16 進位的 RGB 值接在一起
  • "#"+:最後在前面補上井字號

更新 override-color 的值

updateColorsPalette() 裡,我們需要更新的包含:

  1. Color Picker 的索引值 idx,也就是第幾個圖層要換色。
  2. Color Picker 的輸入值 event.target.value,這裡的輸入是 16 進位的色彩值。
function updateColorsPalette(idx, colorValue) {
    const style = document.getElementById("palette-overrides");
    style.innerHTML = `
    @font-palette-values --customize {
        font-family: "Noto Color Emoji";
        base-palette: 0;
        override-colors: ${idx} ${colorValue};
    }
    `;
}

如此一來,我們就能讓使用者選擇指定的顏色,進而替換該圖層的顏色啦:


上一篇
DAY 22|FontKit (2):CPLR 與 CPAL table
下一篇
DAY 24|Emoji Mart:讓使用者挑喜歡的 Emoji
系列文
一起成為新世紀文字藝術師:深入玩轉 Unicode 和 OpenType30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言